﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IPC.Communication.Framework.Reflection;

namespace IPC.Communication.Framework.LogNet
{
    public class LogStatisticsBase<T>
    {
        private T[] statistics = null;

        protected GenerateMode generateMode = GenerateMode.ByEveryDay;

        private int arrayLength = 30;

        private long lastDataMark = -1L;

        private object lockStatistics;

        public GenerateMode GenerateMode
        {
            get
            {
                return this.generateMode;
            }
        }

        public int ArrayLength
        {
            get
            {
                return this.arrayLength;
            }
        }

        public LogStatisticsBase(GenerateMode generateMode, int arrayLength)
        {
            this.generateMode = generateMode;
            this.arrayLength = arrayLength;
            this.statistics = new T[arrayLength];
            this.lastDataMark = this.GetDataMarkFromDateTime(DateTime.Now);
            this.lockStatistics = new object();
        }

        public void Reset(T[] statistics, long lastDataMark)
        {
            bool flag = statistics.Length > this.arrayLength;
            if (flag)
            {
                Array.Copy(statistics, statistics.Length - this.arrayLength, this.statistics, 0, this.arrayLength);
            }
            else
            {
                bool flag2 = statistics.Length < this.arrayLength;
                if (flag2)
                {
                    Array.Copy(statistics, 0, this.statistics, this.arrayLength - statistics.Length, statistics.Length);
                }
                else
                {
                    this.statistics = statistics;
                }
            }
            this.arrayLength = statistics.Length;
            this.lastDataMark = lastDataMark;
        }

        protected void StatisticsCustomAction(Func<T, T> newValue)
        {
            object obj = this.lockStatistics;
            lock (obj)
            {
                long dataMarkFromDateTime = this.GetDataMarkFromDateTime(DateTime.Now);
                bool flag2 = this.lastDataMark != dataMarkFromDateTime;
                if (flag2)
                {
                    int times = (int)(dataMarkFromDateTime - this.lastDataMark);
                    this.statistics = this.GetLeftMoveTimes(times);
                    this.lastDataMark = dataMarkFromDateTime;
                }
                this.statistics[this.statistics.Length - 1] = newValue(this.statistics[this.statistics.Length - 1]);
            }
        }

        protected void StatisticsCustomAction(Func<T, T> newValue, DateTime time)
        {
            object obj = this.lockStatistics;
            lock (obj)
            {
                long dataMarkFromDateTime = this.GetDataMarkFromDateTime(DateTime.Now);
                bool flag2 = this.lastDataMark != dataMarkFromDateTime;
                if (flag2)
                {
                    int times = (int)(dataMarkFromDateTime - this.lastDataMark);
                    this.statistics = this.GetLeftMoveTimes(times);
                    this.lastDataMark = dataMarkFromDateTime;
                }
                long dataMarkFromDateTime2 = this.GetDataMarkFromDateTime(time);
                bool flag3 = dataMarkFromDateTime2 <= dataMarkFromDateTime;
                if (flag3)
                {
                    int num = (int)(dataMarkFromDateTime2 - (dataMarkFromDateTime - (long)this.statistics.Length + 1L));
                    bool flag4 = num >= 0 && num < this.statistics.Length;
                    if (flag4)
                    {
                        this.statistics[num] = newValue(this.statistics[num]);
                    }
                }
            }
        }

        [HslMqttApi(Description = "Get a data snapshot of the current statistics")]
        public T[] GetStatisticsSnapshot()
        {
            return this.GetStatisticsSnapAndDataMark().Content2;
        }

        [HslMqttApi(Description = "Get a snapshot of statistical data information according to the specified time range")]
        public T[] GetStatisticsSnapshotByTime(DateTime start, DateTime finish)
        {
            bool flag = finish <= start;
            T[] result;
            if (flag)
            {
                result = new T[0];
            }
            else
            {
                object obj = this.lockStatistics;
                lock (obj)
                {
                    long dataMarkFromDateTime = this.GetDataMarkFromDateTime(DateTime.Now);
                    bool flag3 = this.lastDataMark != dataMarkFromDateTime;
                    if (flag3)
                    {
                        int times = (int)(dataMarkFromDateTime - this.lastDataMark);
                        this.statistics = this.GetLeftMoveTimes(times);
                        this.lastDataMark = dataMarkFromDateTime;
                    }
                    long num = dataMarkFromDateTime - (long)this.statistics.Length + 1L;
                    long num2 = this.GetDataMarkFromDateTime(start);
                    long num3 = this.GetDataMarkFromDateTime(finish);
                    bool flag4 = num2 < num;
                    if (flag4)
                    {
                        num2 = num;
                    }
                    bool flag5 = num3 > dataMarkFromDateTime;
                    if (flag5)
                    {
                        num3 = dataMarkFromDateTime;
                    }
                    int num4 = (int)(num2 - num);
                    int num5 = (int)(num3 - num2 + 1L);
                    bool flag6 = num2 == num3;
                    if (flag6)
                    {
                        result = new T[]
						{
							this.statistics[num4]
						};
                    }
                    else
                    {
                        T[] array = new T[num5];
                        for (int i = 0; i < num5; i++)
                        {
                            array[i] = this.statistics[num4 + i];
                        }
                        result = array;
                    }
                }
            }
            return result;
        }

        public OperateResult<long, T[]> GetStatisticsSnapAndDataMark()
        {
            object obj = this.lockStatistics;
            OperateResult<long, T[]> result;
            lock (obj)
            {
                long dataMarkFromDateTime = this.GetDataMarkFromDateTime(DateTime.Now);
                bool flag2 = this.lastDataMark != dataMarkFromDateTime;
                if (flag2)
                {
                    int times = (int)(dataMarkFromDateTime - this.lastDataMark);
                    this.statistics = this.GetLeftMoveTimes(times);
                    this.lastDataMark = dataMarkFromDateTime;
                }
                result = OperateResult.CreateSuccessResult<long, T[]>(dataMarkFromDateTime, this.statistics.CopyArray<T>());
            }
            return result;
        }

        [HslMqttApi(Description = "Obtain the latest data mark information according to the time mode of current data statistics")]
        public long GetDataMarkFromTimeNow()
        {
            return this.GetDataMarkFromDateTime(DateTime.Now);
        }

        [HslMqttApi(Description = "According to the specified time, get the data mark information specified at that time")]
        public long GetDataMarkFromDateTime(DateTime dateTime)
        {
            long result;
            switch (this.generateMode)
            {
                case GenerateMode.ByEveryMinute:
                    result = this.GetMinuteFromTime(dateTime);
                    break;
                case GenerateMode.ByEveryHour:
                    result = this.GetHourFromTime(dateTime);
                    break;
                case GenerateMode.ByEveryDay:
                    result = this.GetDayFromTime(dateTime);
                    break;
                case GenerateMode.ByEveryWeek:
                    result = this.GetWeekFromTime(dateTime);
                    break;
                case GenerateMode.ByEveryMonth:
                    result = this.GetMonthFromTime(dateTime);
                    break;
                case GenerateMode.ByEverySeason:
                    result = this.GetSeasonFromTime(dateTime);
                    break;
                case GenerateMode.ByEveryYear:
                    result = this.GetYearFromTime(dateTime);
                    break;
                default:
                    result = this.GetDayFromTime(dateTime);
                    break;
            }
            return result;
        }

        private long GetMinuteFromTime(DateTime dateTime)
        {
            return (long)(dateTime.Date - new DateTime(1970, 1, 1)).Days * 24L * 60L + (long)(dateTime.Hour * 60) + (long)dateTime.Minute;
        }

        private long GetHourFromTime(DateTime dateTime)
        {
            return (long)(dateTime.Date - new DateTime(1970, 1, 1)).Days * 24L + (long)dateTime.Hour;
        }

        private long GetDayFromTime(DateTime dateTime)
        {
            return (long)(dateTime.Date - new DateTime(1970, 1, 1)).Days;
        }

        private long GetWeekFromTime(DateTime dateTime)
        {
            return ((long)(dateTime.Date - new DateTime(1970, 1, 1)).Days + 3L) / 7L;
        }

        private long GetMonthFromTime(DateTime dateTime)
        {
            return (long)(dateTime.Year - 1970) * 12L + (long)(dateTime.Month - 1);
        }

        private long GetSeasonFromTime(DateTime dateTime)
        {
            return (long)(dateTime.Year - 1970) * 4L + (long)((dateTime.Month - 1) / 3);
        }

        private long GetYearFromTime(DateTime dateTime)
        {
            return (long)(dateTime.Year - 1970);
        }

        private T[] GetLeftMoveTimes(int times)
        {
            bool flag = times >= this.statistics.Length;
            T[] result;
            if (flag)
            {
                result = new T[this.arrayLength];
            }
            else
            {
                T[] array = new T[this.arrayLength];
                Array.Copy(this.statistics, times, array, 0, this.statistics.Length - times);
                result = array;
            }
            return result;
        }
    }
}
